/**
 * 1.异步任务队列
 * 2.可配置是否顺序执行
 * 3.传入需要执行的任务列表
 * 4.所有任务执行完毕后返回
 * 5.promise失败后继续执行任务队列
 * 6.返回每个任务的执行结果
 * @returns Promise
 */
const taskQueue = function (taskList = [],isOrder = true) {
    return new Promise((resolve,reject)=>{
        if(taskList.length === 0){
            resolve()
        }
        let taskResult = []
        let taskQueue = taskList.map((task)=>{
            return new Promise((resolve,reject)=>{
                task().then((result)=>{
                    taskResult.push(result)
                    resolve()
                }).catch((err)=>{
                    taskResult.push(err)
                    resolve()
                })
            })
        })
        if(isOrder){
            taskQueue.reduce((prev,next)=>{
                return prev.then(()=>{
                    return next()
                })
            },Promise.resolve()).then(()=>{
                resolve(taskResult)
            })
        }else{
            Promise.all(taskQueue).then(()=>{
                resolve(taskResult)
            })
        }
    })
}
/**
 * 链式调用
 * 1.执行exec方法后返回链式调用结果
 * 2.链式调用的方法可以传入参数
 * 3.链式调用的方法可以传入回调函数
 * 4.链式调用的方法可以传入回调函数的参数
 * 5.链式调用的方法可以传入回调函数的上下文
 * 6.链式调用的方法可以传入回调函数的执行顺序
 * 7.链式调用的方法可以传入回调函数的执行次数
 * 8.链式调用的方法可以传入回调函数的执行间隔
 * @returns 
 */
const chain = function () {
    let chainList = []
    let chainResult = []
    let chainIndex = 0
    let chainContext = null
    let chainExec = function () {
        if(chainIndex === chainList.length){
            return chainResult
        }
        let chainItem = chainList[chainIndex]
        let chainItemResult = chainItem.fn.apply(chainContext,chainItem.args)
        chainResult.push(chainItemResult)
        chainIndex++
        if(chainItem.isAsync){
            setTimeout(()=>{
                chainExec()
            },chainItem.interval)
        }else{
            chainExec()
        }
    }
    let chainFn = function () {
        chainList.push({
            fn:arguments.callee,
            args:[...arguments],
            isAsync:false,
            interval:0
        })
        return chainFn
    }
    chainFn.async = function () {
        chainList.push({
            fn:arguments.callee,
            args:[...arguments],
            isAsync:true,
            interval:0
        })
        return chainFn
    }
    chainFn.interval = function () {
        chainList.push({
            fn:arguments.callee,
            args:[...arguments],
            isAsync:false,
            interval:arguments[0]
        })
        return chainFn
    }
    chainFn.exec = function (context) {
        chainContext = context
        chainExec()
        return chainResult
    }
    return chainFn
}